
/*
dio网络请求框架拦截器
 */
import 'package:dio/dio.dart';
import 'package:xsdk_flutter/xsdk/utils/x_utils_log.dart';

/*
https://blog.csdn.net/fyq520521/article/details/119382876

排队拦截器
Interceptor可以并发执行，即所有请求一次进入拦截器，而不是顺序执行。但是，在某些情况下，我们希望请求按顺序进入拦截器。
方法1:在Interceptor拦截器中加锁;
方法2:使用QueuedInterceptor,它提供一种顺序访问（一个接一个）拦截器的机制。
如:出于安全考虑，我们需要在所有请求的header中设置一个csrfToken，如果csrfToken不存在，我们需要先请求一个csrfToken，
然后再进行网络请求，因为请求csrfToken进度是异步的，所以我们需要在请求拦截器中执行此异步请求;
创建2个不同的Dio实例:
var dio = Dio();
var tokenDio = Dio();
dio.interceptors.add(QueuedInterceptorsWrapper(
    onRequest: (options, handler) {
      print('send request：path:${options.path}，baseURL:${options.baseUrl}');
      if (csrfToken == null) {
        print('no token，request token firstly...');
        tokenDio.get('/token').then((d) {
          options.headers['csrfToken'] = csrfToken = d.data['data']['token'];
          print('request token succeed, value: ' + d.data['data']['token']);
          print(
              'continue to perform request：path:${options.path}，baseURL:${options.path}');
          handler.next(options);
        }).catchError((error, stackTrace) {
          handler.reject(error, true);
        });
      } else {
        options.headers['csrfToken'] = csrfToken;
        return handler.next(options);
      }
    },
   );

   //继续执行响应: handler.next();
    //自定义返回: handler.resolve();
    //直接返回错误: handler.reject()

 */

//(注意:拦截器优先转换器)
// class XHttpInterceptor extends Interceptor {
class XQueuedInterceptor extends QueuedInterceptorsWrapper {

  String interceptorName;

  XQueuedInterceptor(this.interceptorName);

  //请求发送前拦截处理
  @override
  Future<void> onRequest(
      RequestOptions options,
      RequestInterceptorHandler handler,
      ) async
  {

    XLogUtils.printLog('---请求Request[${options.method}],URL= ${options.uri}');//${options.path}
    XLogUtils.printLog('---请求Request,headers= ${options.headers}');
    XLogUtils.printLog('---请求Request= ${options.data}');

    /*
    //判断token过期...
    //锁定拦截器,接下来的请求/响应都会进入请求/响应拦截器之前排队等待,直到当前拦截器解锁才会继续执行
    //dio.lock();已过期废弃,使用QueuedInterceptorsWrapper替代,队列按顺序同步执行达到锁定效果;

    if (csrfToken == null) {
          // 首次获取 csrfToken
          tokenDio.get('/token').then((d) {
            // 这里模拟拿到最新的 csrfToken，并加到 Request headers 中
            options.headers['csrfToken'] = csrfToken = d.data['token'];
            handler.next(options);
          }).catchError((error, stackTrace) {
            handler.reject(error, true);
          });
        } else {
          options.headers['csrfToken'] = csrfToken;
          return handler.next(options);
        }
     */

    //修改headers,url,请求体...
    //options.headers['sign'] = sign;//参数加密签名


    //继续执行响应,注意:成功不能直接使用super.onRequest(options, handler);而要使用handler.next(options);否则将会进入onRequest2次
    return handler.next(options);
  }


  //返回响应数据前拦截处理
  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    //ok拦截器最终修改的响应数据
    //XLogUtils.printLog('---请求拦截器,响应:request-headers(last): ${response.requestOptions.headers}');//注意不能toString()显示格式不一样
    //XLogUtils.printLog('---请求拦截器,响应:response-uri: ${response.uri}');
    //XLogUtils.printLog('---请求拦截器,响应:response-headers: ${response.headers}');
    XLogUtils.printLog('---请求response statusCode:${response.statusCode},url=${response.realUri}, ${response.toString()}');

    // if (response.statusCode == 401) {
    //   // 如果用户未授权，则重定向到登录页面
    //   Navigator.of(context).pushReplacementNamed('/login');
    //   // 由于我们已经处理了这个错误，我们不希望继续抛出错误
    //   // 因此，我们可以使用handler.resolve来直接返回一个成功的响应
    //   return handler.resolve(response);
    // }

    //继续执行响应, 不使用super.onResponse(response, handler);
    handler.next(response);
  }


  //请求失败时处理
  @override
  void onError(DioException err, ErrorInterceptorHandler handler) {
    XLogUtils.printLog('---请求Error: [${err.response?.statusCode}], PATH= ${err.requestOptions.path}');

    // 检查错误类型
    // switch (err.type) {
    //   case DioExceptionType.cancel:
    //   // 处理连接超时错误
    //     break;
    //   case DioExceptionType.sendTimeout:
    //   // 处理发送超时错误
    //     break;
    //   case DioExceptionType.receiveTimeout:
    //   // 处理接收超时错误
    //     break;
    //   case DioExceptionType.badResponse:
    //   // 处理由服务器返回的错误状态码，如404、500等
    //     if (error.response?.statusCode == 404) {
    //       // 处理404错误
    //     }
    //     break;
    //   case DioExceptionType.unknown:
    //   // 处理其他错误，如无网络连接
    //     break;
    //   case DioExceptionType.connectionTimeout:
    //   // 客户端在与服务器建立连接时超出指定的时间限制
    //     break;
    //   case DioExceptionType.badCertificate:
    //   // 处理服务器的 SSL 证书不被客户端信任
    //     break;
    //   case DioExceptionType.connectionError:
    //   // 处理由于网络连接问题失败
    //     break;
    // }



    /*
    //自动重试(原地重试),防网络抖动,再发送请求
    //这里已使用 https://pub-web.flutter-io.cn/packages/dio_smart_retry/install
    if(retryCount<3){
      dio.fetch(options).then(
                  (r) => handler.resolve(r),
              onError: (e) {
                handler.reject(e);
              },
            );
            return;
    }
     */
    //注意:不能直接使用super.onError(err, handler);而要使用handler.next(err);否则将会进入onRequest2次
    //使用handler.next继续传递错误
    handler.next(err);//continue
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is XQueuedInterceptor &&
          runtimeType == other.runtimeType &&
          interceptorName == other.interceptorName;

  @override
  int get hashCode => interceptorName.hashCode;


}